/*
* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* openUBMC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*         http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

#include <gtest/gtest.h>
#include <test_utilities/test_base.h>
#include "cx5_om.h"
#include "cx5_card.h"
#include "cx5_port.h"
#include <mc/engine.h>
#include <mc/common.h>
#include <ctime>
#include <thread>
#include <chrono>

namespace drivers {
namespace pcie_nic_card {
namespace mellanox {
namespace cx5 {
namespace test {

class cx5_test_service : public mc::engine::service {
public:
    cx5_test_service(const std::string& name) : mc::engine::service(name) {}
};

// 辅助函数：清理 cx5_card 的成员变量，避免析构时访问未初始化的指针
static void safe_cleanup_cx5_card(dev::cx5_card* card) {
    if (card == nullptr) {
        return;
    }
    try {
        card->m_network_adapter.stop_ncsi_update_task();
    } catch (...) {
    }
    try {
        card->m_network_adapter_cooling.stop_ncsi_update_task();
    } catch (...) {
    }
    try {
        card->m_pcie_device.stop_ncsi_update_task();
    } catch (...) {
    }
    try {
        card->m_network_adapter.unregister_os_reset_callback();
    } catch (...) {
    }
}

// 自定义删除器：在删除前先清理资源
struct cx5_card_deleter {
    void operator()(dev::cx5_card* card) const {
        safe_cleanup_cx5_card(card);
        delete card;
    }
};

// 辅助函数：清理 cx5_port 的成员变量
static void safe_cleanup_cx5_port(dev::cx5_port* port) {
    if (port == nullptr) {
        return;
    }
    try {
        port->m_network_port.stop_ncsi_update_task();
    } catch (...) {
    }
}

// 自定义删除器：在删除前先清理资源
struct cx5_port_deleter {
    void operator()(dev::cx5_port* port) const {
        safe_cleanup_cx5_port(port);
        delete port;
    }
};

// ========================= cx5_optical_module测试 =========================
class Cx5OpticalModuleTest : public mc::test::TestWithEngine {
protected:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        m_test_service = std::make_unique<cx5_test_service>("bmc.openubmc.test_cx5_om");
        m_test_service->init();
        m_test_service->start();
    }
    static void TearDownTestSuite() {
        try {
            if (m_test_service) {
                m_test_service->stop();
                m_test_service.reset();
            }
            TestWithEngine::TearDownTestSuite();
        } catch (...) {
        }
    }
    void SetUp() override {
        static int test_counter = 0;
        test_counter++;
        std::string card_name = "test_cx5_card_" + std::to_string(test_counter) + "_" + std::to_string(std::time(nullptr));
        std::string port_name = "test_cx5_port_" + std::to_string(test_counter) + "_" + std::to_string(std::time(nullptr));
        std::string om_name = "test_cx5_om_" + std::to_string(test_counter) + "_" + std::to_string(std::time(nullptr));
        std::string position = std::to_string(test_counter + 300);

        // 创建 card
        m_card = mc::make_shared<dev::cx5_card>();
        m_card->set_service(m_test_service.get());
        m_card->set_object_name(card_name.c_str());
        m_card->set_position(position.c_str());
        try {
            m_test_service->register_object(m_card);
        } catch (...) {
            // 忽略注册时的异常，可能在某些测试中不需要注册
        }

        // 创建 port
        m_port = mc::make_shared<dev::cx5_port>();
        m_port->set_service(m_test_service.get());
        m_port->set_object_name(port_name.c_str());
        m_port->set_position((position + "_port").c_str());
        m_port->set_parent(m_card.get());
        try {
            m_test_service->register_object(m_port);
        } catch (...) {
            // 忽略注册时的异常，可能在某些测试中不需要注册
        }

        // 创建 optical_module，设置 parent 为 port
        m_om = mc::make_shared<dev::cx5_optical_module>();
        m_om->set_service(m_test_service.get());
        m_om->set_object_name(om_name.c_str());
        m_om->set_position((position + "_om").c_str());
        m_om->set_parent(m_port.get());
        try {
            m_test_service->register_object(m_om);
        } catch (...) {
            // 忽略注册时的异常，可能在某些测试中不需要注册
        }
    }
    void TearDown() override {
        try {
            // 先清理 optical_module
            if (m_om && m_test_service) {
                try {
                    m_om->stop();
                } catch (...) {
                    // 忽略 stop 时的异常（对象可能未初始化）
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                try {
                    m_test_service->unregister_object(m_om);
                } catch (...) {
                    // 忽略注销时的异常
                }
                m_om.reset();
            }
            // 再清理 port
            if (m_port && m_test_service) {
                try {
                    m_port->stop();
                } catch (...) {
                    // 忽略 stop 时的异常（对象可能未初始化）
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                try {
                    m_test_service->unregister_object(m_port);
                } catch (...) {
                    // 忽略注销时的异常
                }
                m_port.reset();
            }
            // 最后清理 card
            if (m_card && m_test_service) {
                try {
                    m_card->stop();
                } catch (...) {
                    // 忽略 stop 时的异常（对象可能未初始化）
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                try {
                    m_test_service->unregister_object(m_card);
                } catch (...) {
                    // 忽略注销时的异常
                }
                m_card.reset();
            }
        } catch (...) {
            if (m_om) {
                m_om.reset();
            }
            if (m_port) {
                m_port.reset();
            }
            if (m_card) {
                m_card.reset();
            }
        }
    }

    mc::mutable_dict create_test_csr() {
        return mc::mutable_dict{};
    }

    mc::dict create_test_connector() {
        return mc::dict{{"SystemId", 1}};
    }

    static std::unique_ptr<cx5_test_service> m_test_service;
    mc::shared_ptr<dev::cx5_card> m_card;
    mc::shared_ptr<dev::cx5_port> m_port;
    mc::shared_ptr<dev::cx5_optical_module> m_om;
};
std::unique_ptr<cx5_test_service> Cx5OpticalModuleTest::m_test_service;

// ========================= 基本功能测试 =========================

TEST_F(Cx5OpticalModuleTest, Constructor) {
    // Constructor 测试只验证对象能否正确创建
    // cx5_optical_module 没有复杂的析构逻辑，可以直接创建栈对象
    dev::cx5_optical_module om;
    EXPECT_TRUE(true);
}

TEST_F(Cx5OpticalModuleTest, StartStop_Basic) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    m_om->init(csr, connector);

    EXPECT_TRUE(m_om->start());
    EXPECT_TRUE(m_om->stop());
}

TEST_F(Cx5OpticalModuleTest, Init_Success) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    bool result = m_om->init(csr, connector);
    EXPECT_TRUE(result);
}

TEST_F(Cx5OpticalModuleTest, Init_Exception) {
    mc::mutable_dict empty_csr;
    mc::dict empty_connector;
    bool result = m_om->init(empty_csr, empty_connector);
    EXPECT_TRUE(result == true || result == false);
}

TEST_F(Cx5OpticalModuleTest, Init_WithInvalidData) {
    mc::mutable_dict invalid_csr;
    invalid_csr["InvalidKey"] = "invalid_value";
    mc::dict connector = create_test_connector();

    bool result = m_om->init(invalid_csr, connector);
    EXPECT_TRUE(result == true || result == false);
}

// ========================= 多次操作测试 =========================

TEST_F(Cx5OpticalModuleTest, MultipleStartStop) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    m_om->init(csr, connector);

    EXPECT_TRUE(m_om->start());
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    EXPECT_TRUE(m_om->stop());
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
}

// ========================= 异常处理测试 =========================

TEST_F(Cx5OpticalModuleTest, Start_WithoutInit) {
    bool result = m_om->start();
    EXPECT_TRUE(result == true || result == false);
}

TEST_F(Cx5OpticalModuleTest, Stop_WithoutStart) {
    bool result = m_om->stop();
    EXPECT_TRUE(result);
}

TEST_F(Cx5OpticalModuleTest, Stop_AfterStart) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    m_om->init(csr, connector);
    m_om->start();

    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    bool result = m_om->stop();
    EXPECT_TRUE(result);
}

// ========================= 多次调用测试 =========================

TEST_F(Cx5OpticalModuleTest, MultipleInit) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();

    EXPECT_TRUE(m_om->init(csr, connector));
    EXPECT_TRUE(m_om->init(csr, connector));
}

TEST_F(Cx5OpticalModuleTest, MultipleStart) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    m_om->init(csr, connector);

    EXPECT_TRUE(m_om->start());
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    EXPECT_TRUE(m_om->start());
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    EXPECT_TRUE(m_om->stop());
}

TEST_F(Cx5OpticalModuleTest, MultipleStop) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    m_om->init(csr, connector);
    m_om->start();

    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    EXPECT_TRUE(m_om->stop());
    EXPECT_TRUE(m_om->stop());
}

// ========================= 多实例测试 =========================

TEST_F(Cx5OpticalModuleTest, MultiInstance) {
    std::vector<mc::shared_ptr<dev::cx5_optical_module>> oms;
    for (int i = 0; i < 3; i++) {
        std::string object_name = "om_" + std::to_string(i) + "_" + std::to_string(std::time(nullptr)) + "_" + std::to_string(i * 1000);
        std::string position = std::to_string(i + 2000);

        auto om = mc::make_shared<dev::cx5_optical_module>();
        om->set_service(m_test_service.get());
        om->set_object_name(object_name.c_str());
        om->set_position(position.c_str());
        // 设置 parent 为 m_port，但不注册到 service，避免对象路径冲突
        om->set_parent(m_port.get());

        auto csr = create_test_csr();
        auto connector = create_test_connector();
        om->init(csr, connector);
        EXPECT_TRUE(om->start());
        oms.push_back(om);
    }
    for (auto& om : oms) {
        if (om && m_test_service) {
            try {
                om->stop();
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
            } catch (...) {
            }
        }
    }
    oms.clear();
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
}

// ========================= 析构函数测试 =========================

TEST_F(Cx5OpticalModuleTest, Destructor_CleansUpResources) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    m_om->init(csr, connector);
    m_om->start();

    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    m_om->stop();
    m_om.reset();

    EXPECT_TRUE(m_om == nullptr);
}

TEST_F(Cx5OpticalModuleTest, Destructor_WithStart) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    m_om->init(csr, connector);
    m_om->start();

    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    m_om.reset();

    EXPECT_TRUE(m_om == nullptr);
}

} // namespace test
} // namespace cx5
} // namespace mellanox
} // namespace pcie_nic_card
} // namespace drivers

